/**
 * 
 */
package com.ekingstar.framework.service.impl;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.transform.Transformers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;

import com.ekingstar.framework.domain.Function;
import com.ekingstar.framework.domain.FunctionField;
import com.ekingstar.framework.domain.FunctionParameter;
import com.ekingstar.framework.domain.RoleFunctionParamValue;
import com.ekingstar.framework.security.UserUtil;
import com.ekingstar.framework.service.ChangeFunctionEvent;
import com.ekingstar.framework.service.FunctionExistException;
import com.ekingstar.framework.service.IFunctionService;
import com.ekingstar.framework.util.HibernateCallbackUtil;
import com.ekingstar.framework.util.Page;

/**
 * 
 *
 */
public class FunctionServiceImpl implements IFunctionService,ApplicationEventPublisherAware {

	private static Logger log = LoggerFactory.getLogger(FunctionServiceImpl.class);
	/* (non-Javadoc)
	 * @see com.ekingstar.framework.service.IFunctionService#getFunctionsWidthRoles()
	 */
	private HibernateTemplate hibernateTemplate;
	public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
		this.hibernateTemplate = hibernateTemplate;
	}
	public List getFunctionsWidthRoles() {
		// TODO Auto-generated method stub
		StringBuffer funHql = new StringBuffer("select a.id as id,a.addresss as addresss " +
				" from Function a where a.deleteDate is null and (a.filter is null or a.filter =:filter)");
		Map mparams = new HashMap();
		mparams.put("filter", Boolean.TRUE);
		HibernateCallback action = HibernateCallbackUtil.getCallback(funHql, mparams, false, Transformers.aliasToBean(Function.class));
		List functions = (List)hibernateTemplate.execute(action);
		if (functions != null && !functions.isEmpty()){
			for (int i =0 ;i < functions.size();i++){
				Function function = (Function)functions.get(i);
				String fId = function.getId();
				StringBuffer sb = new StringBuffer(" select a.name from Role a " +
						" where a.deleteDate is null and " +
						" a.id in ( select a.TRole.id from RoleFunction a  " +
						" where a.deleteDate is null and a.TFunction.id =:fId ) ");
				Map params = new HashMap();
				params.put("fId", fId);
				action = HibernateCallbackUtil.getCallback(sb, params, false, null);
				List roleIds = (List)hibernateTemplate.execute(action);
				function.setCanUseRoles(roleIds);
			}
		}
		return functions;
	}
	public boolean addFunction(Function func) {
		// TODO Auto-generated method stub
		if (func.getParent()!= null && func.getParent().getId() != null && !func.getParent().getId().trim().equals("")){
			Function parentFunction = (Function)hibernateTemplate.get(Function.class, func.getParent().getId());
			func.setParent(parentFunction);
		}
		else {
			func.setParent(null);
		}
		func.setAdderId(UserUtil.getCurrentUserId());
		func.setAddDate(new Date());
		hibernateTemplate.save(func);
		checkExistFuncion(func);
		if (Boolean.TRUE.equals(func.getLeaf())){
			List fields = func.getFields();
			if (fields != null && fields.size() > 0){
				for (int i = 0 ;i  < fields.size();i++){
					FunctionField ff = (FunctionField)fields.get(i);
					ff.setAdderId(UserUtil.getCurrentUserId());
					ff.setAddDate(new Date());
					ff.setFunction(func);
					hibernateTemplate.save(ff);
				}
			}
			List params = func.getParams();
			if (params != null && params.size() > 0){
				for (int i = 0 ;i  < params.size();i++){
					FunctionParameter ff = (FunctionParameter)params.get(i);
					ff.setFunctionId(func.getId());
					hibernateTemplate.save(ff);
				}
			}
		}
		applicationEventPublisher.publishEvent(new ChangeFunctionEvent(this));
		return true;
	}
	public boolean deleteFunction(String id) {
		// TODO Auto-generated method stub
		Function function = (Function)hibernateTemplate.get(Function.class, id);
		function.setDeleteDate(new Date());
		function.setDeleterId(UserUtil.getCurrentUserId());
		return false;
	}
	//
	private void getUserChildenFunction(Function fun,String uId){
		if (fun == null || fun.getId() == null || uId == null) return;
		StringBuffer sb  = new StringBuffer(" select distinct e.id as id,e.name as name,e.addresss as addresss,b.can_use as canUse " +
				" from t_user a,t_user_role b,t_role_function c,t_role d ,t_function e  " +
				" where e.parent_id=:pId and b.can_use=:canUse and b.user_id=a.id and b.role_id=d.id and c.role_id=d.id and c.function_id= e.id and a.id=:id " +
				" and b.delete_date is null and d.delete_date is null and c.delete_date is null and e.delete_date is null ");
		Map params = new HashMap();
		Map scalars = new HashMap();
		scalars.put("id", Hibernate.STRING);
		scalars.put("name", Hibernate.STRING);
		scalars.put("addresss", Hibernate.STRING);
		scalars.put("canUse", Hibernate.BOOLEAN);
		params.put("id", uId);
		params.put("canUse", Boolean.TRUE);
		params.put("pId", fun.getId());
		//
		HibernateCallback action = HibernateCallbackUtil.getNativeCallback(sb, params, false, scalars, Transformers.aliasToBean(Function.class));
		List res = (List)hibernateTemplate.execute(action);
		if (res != null && !res.isEmpty()){
			fun.setChilden(res);
			for (int i = 0 ;i  < res.size();i++){
				Function function = (Function)res.get(i);
				function.setParent(fun);
				getUserChildenFunction(function,uId);
			}
		}
		
	}
	public List<Function> getFunctionsByUserId(String id) {
		// TODO Auto-generated method stub
		List res = new ArrayList();
		List list=new ArrayList();
		try
		{
			if (id == null || id.trim().equals("")) return null;
			StringBuffer sb  = new StringBuffer(" select  e.id as id,e.parent_id as parentId,e.name as name," +
					" e.addresss as addresss,e.is_leaf as leaf,e.is_show as \"show\",e.order_num as orderNum," +
					" b.can_use as canUse " +
					" from t_user a,t_user_role b,t_role_function c,t_role d ,t_function e  " +
					" where  b.can_use=:canUse and b.user_id=a.id and b.role_id=d.id and c.role_id=d.id and c.function_id= e.id and a.id=:id " +
					" and b.delete_date is null and d.delete_date is null and c.delete_date is null and e.delete_date is null ");
			Map params = new HashMap();
			Map scalars = new HashMap();
			scalars.put("id", Hibernate.STRING);
			scalars.put("name", Hibernate.STRING);
			scalars.put("addresss", Hibernate.STRING);
			scalars.put("leaf", Hibernate.BOOLEAN);
			scalars.put("show", Hibernate.BOOLEAN);
			scalars.put("parentId", Hibernate.STRING);
			scalars.put("canUse", Hibernate.BOOLEAN);
			scalars.put("orderNum", Hibernate.FLOAT);
			params.put("id", id);
			params.put("canUse", Boolean.TRUE);
			//
			//sb.append(" order by e.parent_id,e.order_num ");
			sb.append(" order by e.order_num ");
			HibernateCallback action = HibernateCallbackUtil.getNativeCallback(sb, params, false, scalars, Transformers.aliasToBean(Function.class));
			res = (List)hibernateTemplate.execute(action);
		}
		catch(Exception ex)
		{
			ex.printStackTrace();
		}
	
		//子功能
		list=generateFunctionStructure(res);
		return list;
		
	}
	private List generateFunctionStructure(List functions){
		List res = new ArrayList();
		try
		{
			if (functions== null || functions.isEmpty() )return null;
		
			List allFunctions = new LinkedList();
			
			
			Function tempParentFun = new Function();
			for (int i = 0; i < functions.size();i++){
				Function fun = (Function)functions.get(i);
				
				while(true){
					if ( fun.getParentId() != null){
						Function parent = null;
						tempParentFun.setId(fun.getParentId());
						int index = allFunctions.indexOf(tempParentFun);
						if (index >= 0 ){
							parent = (Function)allFunctions.get(index);
						}else {
							parent = (Function)hibernateTemplate.get(Function.class, fun.getParentId());
							allFunctions.add(parent);
						}
						
						if (parent.getChilden().indexOf(fun) < 0){
							parent.getChilden().add(fun);
						}
						
						if (parent.getParent() != null){
						 parent.setParentId(parent.getParent().getId());
						}
						fun = parent;
					}
					else{
						if (res.indexOf(fun) <0){
							res.add(fun);
						}
						break;
					}
				}
				
			}
		}
		catch(Exception ex)
		{
			ex.printStackTrace();
		}
		if (res != null && !res.isEmpty()){
			Collections.sort(res, new Comparator<Function>(){
				public int compare(Function f1, Function f2) {
					// TODO Auto-generated method stub
					//System.out.println("f1:"+f1.getOrderNum()+" f2:"+f2.getOrderNum());
					if (f1 != null  && f2 != null && f1.getOrderNum() != null && f2.getOrderNum() != null){
						return f1.getOrderNum().compareTo(f2.getOrderNum());
					}
					return 0;
				}
			});
		}
		return res;
	}
	
	public boolean updateFunction(final Function func) {
		// TODO Auto-generated method stub
		if (func == null || func.getId() == null)  return false;
		
		final Function function = (Function)hibernateTemplate.get(Function.class, func.getId().trim());		
		
		function.setUpdaterId(UserUtil.getCurrentUserId());
		function.setLastUpdateDate(new Date());
		function.setAddresss(func.getAddresss());
		function.setOrderNum(func.getOrderNum());
		function.setName(func.getName());
		function.setParent(func.getParent());
		function.setShow(func.getShow());
		function.setFilter(func.getFilter());
		function.setFunctionCode(func.getFunctionCode());
		function.setFunctionType(func.getFunctionType());
		hibernateTemplate.save(function);
		checkExistFuncion(function);
		//操作
		hibernateTemplate.execute(new HibernateCallback(){
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query query = session.createQuery("update FunctionField a set a.deleteDate = :now,a.deleterId=:user where a.function=:fun");
				query.setParameter("now", new Date());
				query.setParameter("fun",func);
				query.setParameter("user", UserUtil.getCurrentUserId());
				query.executeUpdate();
				//
				if (Boolean.TRUE.equals(function.getLeaf())){
					List fields = func.getFields();
					if (fields != null && fields.size() > 0){
						for (int i = 0 ;i  < fields.size();i++){
							FunctionField ff = (FunctionField)fields.get(i);
							ff.setAdderId(UserUtil.getCurrentUserId());
							ff.setAddDate(new Date());
							ff.setFunction(func);
							session.save(ff);
						}
					}
				}
				return null;
			}
		});
		//功能参数				
		hibernateTemplate.execute(new HibernateCallback(){
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				
//				Query query = session.createQuery("delete from FunctionParameter a  where functionId=:fun");
//				query.setParameter("fun",func.getId());
//				query.executeUpdate();
//				//
//				if (Boolean.TRUE.equals(function.getLeaf())){
//					List params = func.getParams();
//					if (params != null && params.size() > 0){
//						for (int i = 0 ;i  < params.size();i++){
//							FunctionParameter ff = (FunctionParameter)params.get(i);
//							ff.setFunctionId(function.getId());
//							session.save(ff);
//						}
//					}
//				}
				
				String oldpara="";
				Query query = session.createQuery("select a " +
						" from FunctionParameter a where a.functionId=:fun");
				query.setParameter("fun",function.getId());
				List oldparams =query.list();				
				if(oldparams!=null&&oldparams.size()>0){
					for(int i=0;i<oldparams.size();i++){
						FunctionParameter fpm=(FunctionParameter)oldparams.get(i);
						String pid=fpm.getId();
						oldpara+=pid+",";
					}
				}
				
				String newpara="";
				List newparams=func.getParams();
				if(newparams!=null&&newparams.size()>0){
					for(int i=0;i<newparams.size();i++){
						FunctionParameter fpm=(FunctionParameter)newparams.get(i);
						String pid=fpm.getId();
						if(pid!=null&&pid.length()>0){
							newpara+=pid+",";
						
							if(oldpara.indexOf(pid)!=-1){//修改参数
								FunctionParameter functionparameter=(FunctionParameter)session.get(FunctionParameter.class, pid);
								functionparameter.setParameterName(fpm.getParameterName());
								functionparameter.setParameterGroup(fpm.getParameterGroup());
								functionparameter.setParameterType(fpm.getParameterType());
								functionparameter.setRemark(fpm.getRemark());
								session.update(functionparameter);
							}
						}
						else{//新增参数
							fpm.setFunctionId(function.getId());
							session.save(fpm);
						}
					}
				}
				
				if(oldparams!=null&&oldparams.size()>0){
					for(int i=0;i<oldparams.size();i++){
						FunctionParameter fpm=(FunctionParameter)oldparams.get(i);
						String pid=fpm.getId();
						if(newpara.indexOf(pid)==-1){//删除参数
							query = session.createQuery("delete from RoleFunctionParamValue a  where paramId=:para");
							query.setParameter("para",pid);
							query.executeUpdate();
							
							session.delete(fpm);							
						}

					}
				}	
				
				return null;
	
			}
		});
		applicationEventPublisher.publishEvent(new ChangeFunctionEvent(this));
		return true;
	}
	public Function viewFunction(String id) {
		// TODO Auto-generated method stub
		if (id == null || id.trim().equals("")) return null;
		Function function = (Function)hibernateTemplate.get(Function.class, id);
		if (function.getParent() != null){
			function.getParent().getName();
		}
		List roles = hibernateTemplate.findByNamedParam("select a.TRole " +
				" from RoleFunction a where a.deleteDate is null and a.TFunction=:fun  ", "fun", function);
		function.setRoles(roles);
		List fields = hibernateTemplate.findByNamedParam("select a " +
				" from FunctionField a where a.deleteDate is null and a.function=:fun and a.fieldClass='3' ", "fun", function);
		function.setFields(fields);
		List params = hibernateTemplate.findByNamedParam("select a " +
				" from FunctionParameter a where a.functionId=:fun ", "fun", function.getId());
		function.setParams(params);
		return function;
	}
	//��ȡӵ��
	public Page queryFunctions(Function condtion, int pageNo, int pageSize) {
		// TODO Auto-generated method stub
		if (pageNo <= 0) pageNo = 1;
		StringBuffer sb = new StringBuffer("select a.id as id,a.name as name,a.functionCode as functionCode,a.filter as filter,a.show as show,a.orderNum as orderNum,a.leaf as leaf," +
				" a.addresss as addresss," +
				" b.name as parentName,b.id as parentId " +
				"  from Function a left join a.parent b  where a.deleteDate is null ");
		Map params = new HashMap();
		if (condtion != null){
			if (condtion.getName() != null && !condtion.getName().trim().equals("")){
				sb.append(" and a.name like :name");
				params.put("name", "%"+condtion.getName().trim()+"%");
			}if (condtion.getAddresss() != null && !condtion.getAddresss().trim().equals("")){
				sb.append(" and a.addresss like :addresss");
				params.put("addresss", "%"+condtion.getAddresss().trim()+"%");
			}
			if (condtion.getParent() != null && condtion.getParent().getId() != null && !condtion.getParent().getId().trim().equals("")){
				sb.append(" and a.parent.id =:id ");
				params.put("id", condtion.getParent().getId());
			}
			
		}
		sb.append(" order by b.name,a.orderNum asc ");
		HibernateCallback action = HibernateCallbackUtil.getCallbackWithPage(sb, params,Transformers.aliasToBean(Function.class), pageNo, pageSize);
		Page page = (Page)hibernateTemplate.execute(action);
		return page;
	}

	private void checkExistFuncion(Function func){
		if (func == null) return;
		//检查功能号
		if (func.getFunctionCode() != null && !func.getFunctionCode().trim().equals("")){
			List res = hibernateTemplate.findByNamedParam("select count(*) from Function a " +
				" where a.functionCode=:code and a.deleteDate is null ", "code", func.getFunctionCode().trim()); 
			if (res != null && res.size() > 0){
				Number count = (Number)res.get(0);
				if (count.intValue() > 1) throw new FunctionExistException("功能号重复!");
			}
		}
		if (func.getName() != null && !func.getName().trim().equals("")){
			List res = hibernateTemplate.findByNamedParam("select count(*) from Function a " +
					" where a.name=:name and a.deleteDate is null and a.parent=:parent", 
					new String[]{"name","parent"}, new Object[]{func.getName().trim(),func.getParent()}); 
				if (res != null && res.size() > 1){
					Number count = (Number)res.get(0);
					if (count.intValue() > 0) throw new FunctionExistException("同一层中有相同的功能名!");
				}
		}
	}
	
	public List getFunctionStructure(boolean isIncludeLeaf) {
		List res = hibernateTemplate.find(" from Function a where a.parent is null and a.deleteDate is null");
		if (res != null && !res.isEmpty()){
			for (int i = 0;i < res.size();i++){
				Function fun = (Function)res.get(i);
				getChildenByFunctionId(fun,isIncludeLeaf);
				
			}
		}
		// TODO Auto-generated method stub
		return res;
	}
	private List  getChildenByFunctionId(Function fun,boolean isIncludeLeaf){
		if (fun == null ) return null;
		List children =  hibernateTemplate.findByNamedParam(" from Function a " +
				" where  a.deleteDate is null and a.parent is not null and a.parent.id=:id","id",fun.getId());
		if (children != null && !children.isEmpty()){
			for (int i = 0;i < children.size();i++){
				Function cfun = (Function)children.get(i);
				List tempChilden = getChildenByFunctionId(cfun,isIncludeLeaf);
				
				if (isIncludeLeaf){
					fun.getChilden().add(cfun);
				}
				else if (tempChilden != null && tempChilden.size() > 0){
						fun.getChilden().add(cfun);
				}
			}
		}
		return children;
	}
	public List<Function> getChildren(String fid) {
		// TODO Auto-generated method stub
		List children = null;
		if (fid == null || fid.trim().equals("")){
			 children =  hibernateTemplate.find(" from Function a " +
					" where  a.deleteDate is null and a.parent is  null");
			
		}
		else {
			 children =  hibernateTemplate.findByNamedParam(" from Function a " +
					" where  a.deleteDate is null and a.parent.id=:id","id",fid);
		}
		return children;
	}
	public List<FunctionField> getFunctionField(String fid) {
		// TODO Auto-generated method stub
		if (fid == null || fid.trim().equals("")) return null;
		List fields =  hibernateTemplate.findByNamedParam(" from FunctionField a " +
				" where  a.deleteDate is null and a.function.id=:id and a.fieldClass='3' order by a.fieldClass ","id",fid);
		return fields;
	}
	public void setApplicationEventPublisher(
			ApplicationEventPublisher applicationEventPublisher) {
		// TODO Auto-generated method stub
		this.applicationEventPublisher = applicationEventPublisher;
		
	}
	private ApplicationEventPublisher applicationEventPublisher = null;
	public List<Function> getChildren(Function parent) {
		// TODO Auto-generated method stub
		if (parent == null){
			return (List)hibernateTemplate.execute(new HibernateCallback(){
				public Object doInHibernate(Session session)
						throws HibernateException, SQLException {
					// TODO Auto-generated method stub
					Query query = session.createQuery(" select a  from Function a " +
							" where  a.deleteDate is null and a.parent is  null");
					query.setResultTransformer(new ResultTransformer(){

						public List transformList(List collection) {
							// TODO Auto-generated method stub
							return collection;
						}
						public Object transformTuple(Object[] tuple,
								String[] aliases) {
							// TODO Auto-generated method stub
							Function fun  = (Function)tuple[0];
							fun.setParentName(fun.getParent() == null?"":fun.getParent().getName());
							return fun;
						}
					});
					 List res = query.list();
					return res;
				}
			});
		}
		return null;
	}
	//
	public List getFunctionParameter(final String fid, final String rid) {
		// TODO Auto-generated method stub
		if (fid == null || fid.trim().equals("")) return null;
		if (rid == null || rid.trim().equals("")) return null;
		
		List params = hibernateTemplate.findByNamedParam("select new Map(a.id as id,a.functionId as functionId," +
				" a.parameterName as parameterName,a.remark as remark,a.parameterGroup as parameterGroup,a.parameterType as parameterType)" +
				"  from FunctionParameter a " +
				" where a.functionId=:fid", "fid", fid.trim());
		if (params == null || params.isEmpty()) return null;
		for (int i = 0;i < params.size();i++){
			Map temp = (Map)params.get(i);
			String id=(String)temp.get("id");
			List res = hibernateTemplate.findByNamedParam("select a.paramValue " +
					"from RoleFunctionParamValue a where a.paramId =:pId and a.roleId=:rId",
					new String[]{"pId","rId"}, new Object[]{id,rid});
			if (res != null && res.size()>0){
				String val = (String)res.get(0);
				temp.put("paramValue", val);
			}
		}
		
		return params;
	}
	
}
